#!/usr/bin/python
# coding=UTF-8
import sys
import random
import math
import time
import os
import requests
import configparser
import subprocess
import MySQLdb
import json
import _thread
import uuid
import urllib.request
from urllib.parse import urlencode
import ccxt

thread_alive = {}
pending_order = {}
all_ticker = {}
platform_ticker_time = {}

def get_conf(name):
    cp = configparser.ConfigParser()
    the_dir = sys.path[0]
    # print(the_dir)
    cp.read(the_dir+'/db.conf')
    return cp.get('db', name)


def Conn():
    cp = configparser.ConfigParser()
    the_dir = sys.path[0]
    print(the_dir)
    cp.read(the_dir+'/db.conf')
    return MySQLdb.connect(host=cp.get('db', 'host'), user=cp.get('db', 'user'), passwd=cp.get('db', 'pass'), db=cp.get('db', 'name'), port=int(cp.get('db', 'port')), charset=cp.get('db', 'charset'))
    # return MySQLdb.connect(host='127.0.0.1',user='root',passwd='root',db='testdb',port=3306, charset="utf8")

def getAllTick(platform):
    if platform in platform_ticker_time:
        last_time = platform_ticker_time[platform]
        now_time =  int(time.time())
        if now_time- last_time < 5:
            print('fetch', platform, 'ticker pass , wait next time')
            return
    exchange_id = platform
    if exchange_id == 'huobi':
        exchange_id = 'huobipro'
    exchange_class = getattr(ccxt, exchange_id)
    exchange = exchange_class({
        #'apiKey': api_key,
        #'secret': secret_key,
        #'password': passphrase,        
        'timeout': 30000,
        'enableRateLimit': True,
        'rateLimit': 4000,
    })
    try:
        #print('fetch', platform, 'ticker : ', market)
        #ticker_data = exchange.fetch_ticker(market)
        print('fetch', platform, 'ticker')
        ticker_data = exchange.fetch_tickers()     
        #print(ticker_data)
        if isinstance(ticker_data,dict):
            for ticker_item in ticker_data:
                #print(ticker_item)
                #print(ticker_data[ticker_item]['last'])
                if platform not in all_ticker:
                    all_ticker[platform] = {}
                all_ticker[platform][ticker_item] = ticker_data[ticker_item]
            platform_ticker_time[platform] = int(time.time())
        else:
            print(ticker_data)
    except Exception as e:
        print(e)
        return None    
        
def getTick(platform, api_info, market):
    getAllTick(platform)
    #print(all_ticker[platform])
    try:
        print('fetch', platform, 'ticker : ', market)
        if platform in all_ticker:
            if market in all_ticker[platform]:
                print(platform, ' ', market, ' price:', all_ticker[platform][market]['last'])
                return all_ticker[platform][market]['last']
        else:
            #print(all_ticker)
            print('fetch', platform, 'ticker ', market,': error')
            return None
    except Exception as e:
        print(e)
        return None

# jinglan tick
def getLocalTick(params):
    host = 'http://' + get_conf('corehost') + ':8080'
    headers = {'Content-Type': 'application/json', 'Connection': 'close'}
    post_data = {"id": 22, "method": "market.last", "params": params}
    encode_json = json.dumps(post_data)
    # print encode_json
    try:
        P_post = requests.post(host, headers=headers,
                               data=encode_json, timeout=5)
        if P_post.status_code == 200:
            rst = json.loads(P_post.text)
            # print rst
            if 'result' in rst:
                return rst['result']
            else:
                return None
        else:
            return None
    except Exception as e:
        print(e)
        return None

# 市价
def order(robot_id,side, api_info, market, amount):
    ret = {}
    #print(pending_order)
    if robot_id in pending_order:
        if pending_order[robot_id] == 1:
            ret['code'] = 0
            ret['data'] = {}
            ret['msg'] = 'wait pending order,robot:'+str(robot_id)
            #print(pending_order)
            return ret
        else:
            pending_order[robot_id] = 1
    else:
        pending_order[robot_id] = 1
    
    platform = api_info['platform']
    api_key = api_info['api_key']
    secret_key = api_info['secret_key']
    passphrase = api_info['passphrase']
    exchange_id = platform
    if exchange_id == 'huobi':
        exchange_id = 'huobipro'    
    exchange_class = getattr(ccxt, exchange_id)
    exchange = exchange_class({
        'apiKey': api_key,
        'secret': secret_key,
        'password': passphrase,
        'timeout': 30000,
        'enableRateLimit': True,
        'options': {
            'createMarketBuyOrderRequiresPrice': False,
        },
    })
    # if platform == 'okex':
    #     exchange.hostname = 'okexcn.com'
    #     exchange.urls['api']['rest'] = 'https://www.okexcn.com'
    # if platform == 'binance':
    #     exchange.urls['api']['v1'] = 'https://api.binancezh.cc/api/v1'
    #     exchange.urls['api']['v3'] = 'https://api.binancezh.cc/api/v3'
    #     exchange.urls['api']['private'] = 'https://api.binancezh.cc/api/v3'
    #     exchange.urls['api']['public'] = 'https://api.binancezh.cc/api/v3'
    try:
        # 卖
        if side == 1:
            result = exchange.create_market_sell_order(market, amount)
        else:
            # 买入
            print(market)
            print(amount)
            result = exchange.create_market_buy_order(
                market, amount, {'quoteOrderQty': amount})
        print(result)
        
        # deal_result = exchange.fetch_order('199284377498128')
        # print(deal_result)
        # return;
        order_info = {}
        order_info['order_id'] = result['id']
        if platform == 'okex':
            deal_result = exchange.fetch_order_trades(result['id'], market)
            print(deal_result)
            while len(deal_result) == 0:
                time.sleep(0.5)
                deal_result = exchange.fetch_order_trades(result['id'], market)
                print(deal_result)
            order_info['deal_money'] = deal_result[0]['cost']
            order_info['deal_stock'] = deal_result[0]['amount']
            order_info['deal_fee'] = deal_result[0]['fee']['cost']
        elif platform == 'huobi':
            deal_result = exchange.fetch_order(result['id'])
            print(deal_result)
            while len(deal_result) == 0:
                time.sleep(0.5)
                deal_result = exchange.fetch_order(result['id'])
                print(deal_result)
            order_info['deal_money'] = deal_result['cost']
            order_info['deal_stock'] = deal_result['amount']
            order_info['deal_fee'] = deal_result['fee']['cost']
        else:
            order_info['deal_money'] = result['cost']
            order_info['deal_stock'] = result['amount']
            order_info['deal_fee'] = result['fee']['cost']
        ret['code'] = 1
        ret['data'] = order_info
        ret['msg'] = 'success'
        pending_order[robot_id] = 0
        return ret
    except Exception as e:
        print(e)
        ret['code'] = 0
        ret['data'] = {}
        ret['msg'] = str(e)
        pending_order[robot_id] = 0
        return ret

# jinlan市价交易
def localOrder(side, token, market, amount):
    ret = {}
    try:
        textmod = {"access_token": token, "type": 2, "market": str(
            market), "side": side, "amount": str(amount), "pride": 0}
        textmod = urlencode(textmod)
        url = 'https://' + get_conf('domain') + '/api/exchange/order-limit'
        req = urllib.request.Request(url, textmod.encode())
        opener = urllib.request.urlopen(req)
        res = json.loads(opener.read().decode())
        order_info = {}
        if 'code' in res and res['code'] == 200:
            order_result = res['data']
            order_info['order_id'] = order_result['id']
            order_info['deal_money'] = order_result['deal_money']
            order_info['deal_stock'] = order_result['deal_stock']
            order_info['deal_fee'] = order_result['deal_fee']
            ret['code'] = 1
            ret['data'] = order_info
            ret['msg'] = 'success'
        else:
            ret['code'] = 0
            ret['data'] = {}
            ret['msg'] = res['message']
        print('===========jinlan市价交易============')
        print(ret)
        return ret
    except Exception as e:
        ret['code'] = 0
        ret['data'] = {}
        ret['msg'] = str(e)
        return ret

def updateMsg(robot_id, show_msg):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set show_msg = '%s' where id = %d" % (
        show_msg, robot_id)
    print(update_sql)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()


def updateValues(robot_id, values_str):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set values_str = '%s' where id = %d" % (
        values_str, robot_id)
    print(update_sql)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()


def updateRevenue(robot_id, revenue):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set revenue = '%s' where id = %d" % (
        revenue, robot_id)
    print(update_sql)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()


def disableRobot(robot_id):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set status = 0 where id = %d" % robot_id
    print(update_sql)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()


def cleanFinish(robot_id):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set is_clean = 0 where id = %d" % robot_id
    print(update_sql)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()


def insertLog(platform, robot_id, uid, log):
    conn = Conn()
    cur = conn.cursor(MySQLdb.cursors.DictCursor)
    cur.execute(
        "select id,content from jl_quant_robot_log where qrobot_id = %d order by id desc limit 0,1" % robot_id)
    last_log = cur.fetchone()
    if last_log:
        if last_log['content'] == log:
            return
    insert_sql = "insert jl_quant_robot_log(platform,uid,qrobot_id,content) values ('%s',%d,%d,'%s')" % (
        platform, uid, robot_id, log)
    print(insert_sql)
    cur.execute(insert_sql)
    conn.commit()
    cur.close()
    conn.close()


def insertRevenueLog(platform, robot_id, pid, uid, market, stock, money, revenue):
    conn = Conn()
    cur = conn.cursor()
    insert_sql = "insert jl_quant_robot_revenue(platform,qrobot_id,pid,uid,market,stock,money,revenue,deal_status) values ('%s',%d,'%s',%d,'%s','%s','%s','%s',%d)" % (platform,
                                                                                                                                                                       robot_id, pid, uid, market, stock, money, revenue, 0)
    print(insert_sql)
    cur.execute(insert_sql)
    conn.commit()
    cur.close()
    conn.close()


def insertOrder(platform, uid, order_id, robot_id, side, market, stock, money, deal_money, deal_amount, price, is_first, uuid,deal_fee,revenue):
    conn = Conn()
    cur = conn.cursor()
    insert_sql = "insert jl_quant_robot_order(platform,uid,qrobot_id,side,market,stock,money,deal_money,deal_amount,price,order_status,is_first,pid,deal_fee,revenue) values ('%s',%d,%d,%d,'%s','%s','%s','%s','%s','%s',1,%d,'%s','%s','%s')" % (
        platform, uid, robot_id, side, market, stock, money, deal_money, deal_amount, price, is_first, uuid,deal_fee,revenue)
    print(insert_sql)
    cur.execute(insert_sql)
    conn.commit()

def getRobotConfig(robot_id):
    conn = Conn()
    cur = conn.cursor(MySQLdb.cursors.DictCursor)
    cur.execute("SELECT * from jl_quant_robot where status = 1 and id = %d" % robot_id)
    robot = cur.fetchone()
    return robot

def getOrder(order_id):
    conn = Conn()
    cur = conn.cursor(MySQLdb.cursors.DictCursor)
    cur.execute("SELECT * from jl_quant_robot_order where order_status = 1 and clean_status = 0 and is_clean = 1 and side=2 and id = %d" % order_id)
    robot = cur.fetchone()
    return robot

def updateLoopNum(robot_id,loop_num):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set loop_num = '%s' where id = %d" % (
        loop_num, robot_id)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()

def updateCoverNum(robot_id,cover_num):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set cover_num = '%s' where id = %d" % (
        cover_num, robot_id)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()

def updateCoverStr(robot_id,cover_str):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set cover_str = '%s' where id = %d" % (
        cover_str, robot_id)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()

def updateOder(robot_id,clean_status):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot_order set clean_status = '%s' where id = %d" % (
        clean_status, robot_id)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()

def updateNowCoverNum(robot_id,now_cover_num):
    conn = Conn()
    cur = conn.cursor()
    update_sql = "update jl_quant_robot set now_cover_num = '%s' where id = %d" % (
        now_cover_num, robot_id)
    cur.execute(update_sql)
    conn.commit()
    cur.close()
    conn.close()

# 策略主函数
def onTick(order_id, market_info, api_info,robot_config):
    order_config = getOrder(order_id) 
    if not order_config:
        print('------order is empty-------')
        return
    if order_config is  None:
        print('------order is none-------')        
        return
    market = market_info['market_name']
    stock_name = market_info['stock']
    money_name = market_info['money']
    market_type = market_info['type']
    robot_id = order_config['id']
    platform = order_config['platform']
    uid = order_config['uid']
    qrobot_id = order_config['qrobot_id']
    # print(market)
    #check thread
    print(thread_alive)
    if robot_id in thread_alive:
        if thread_alive[robot_id] == 1:
            print('wait pending thread,robot:'+str(robot_id))
            return
        else:
            thread_alive[robot_id] = 1
    else:
        thread_alive[robot_id] = 1

        rst = order(robot_id,1, api_info, market,order_config['deal_amount'])
        print(rst)
        if rst['code'] == 1:
            order_id = rst['data']['order_id']
            deal_money = rst['data']['deal_money']
            deal_amount = rst['data']['deal_stock']
            deal_fee = rst['data']['deal_fee']
            price = float(deal_money)/float(deal_amount)
            side = 1
            deal_money = float(deal_money)-float(deal_fee)
            revenue = float(deal_money) - \
                float(order_config['deal_money'])
            insertOrder(platform, uid, order_id, qrobot_id, side, market, stock_name,
                        money_name, deal_money, deal_amount, price, 2, robot_id,deal_fee,revenue)
            insertRevenueLog(
                platform, qrobot_id, robot_id, uid, market, stock_name, money_name, revenue)
            updateRevenue(qrobot_id, 0)
            updateOder(robot_id, 1)
            insertLog(platform, qrobot_id, uid, u"清仓卖出：成交总价 %s %s ,成交均价 %s %s,成交数量 %s %s" % (
                deal_money, money_name, price, money_name, deal_amount, stock_name))
            values_str = robot_config['values_str']
            if values_str:
                values_dict = json.loads(values_str)
                values_dict['deal_amount'] = float(values_dict['deal_amount']) - float(order_config['deal_amount'])
                updateValues(qrobot_id, json.dumps(values_dict))
            thread_alive[robot_id] = 0
            return
        else:
            updateMsg(qrobot_id, u'清仓卖出失败' + rst['msg'])
            insertLog(platform, qrobot_id, uid,
                        u'清仓卖出失败' + rst['msg'])
            thread_alive[robot_id] = 0
            return

# 读取所有的策略配置
def loadStrategyConfig(cur):
     # read db
    markets_count = cur.execute(
        "select id,platform,market,market_name,type,stock,money from jl_spot_market where status = 1")
    print('db have %d market' % markets_count)
    markets = cur.fetchall()
    # print(markets)
    market_list = {}
    for market in markets:
        market_list[market['id']] = market
    # print(market_list)
    # read api key
    api_count = cur.execute(
        "select id,uid,platform,api_key,secret_key,passphrase from jl_third_api where status = 1")
    print('db have %d api' % api_count)
    apis = cur.fetchall()
    # print(apis)
    api_list = {}
    for api in apis:
        api_list["%s-%s" % (api['platform'], api['uid'])] = api
    # print(api_list)
    cur.execute('SELECT * from jl_quant_robot_order where side = 2 and is_clean = 1 and order_status = 1 and clean_status=0')
    robots = cur.fetchall()
    if robots:
        for robot in robots:
            robotConfig = getRobotConfig(robot['qrobot_id'])
            market_id = robotConfig['market_id']
            platform = robotConfig['platform']
            uid = robot['uid']
            order_id = robot['id']
            if market_id in market_list:
                market_info = market_list[market_id]
            else:
                print('market %s  not found , stopped...' % market_id)
                continue
            if "%s-%s" % (platform, uid) in api_list:
                api_info = api_list["%s-%s" % (platform, uid)]
            else:
                print('%s api not found , stopped...' % platform)
                continue
            _thread.start_new_thread(
                onTick, (order_id, market_info, api_info,robotConfig))
    else:
        print(u'no order , wait ...')


while True:
    try:
        conn = Conn()
        cur = conn.cursor(MySQLdb.cursors.DictCursor)
        loadStrategyConfig(cur)
        cur.close()
        conn.close()
        time.sleep(1)
    except Exception as e:
        print(Exception, ':', e)
        time.sleep(3)
